/**
 * 三级错误处理
 * 1、网络错误, 包含断网，弱网等，断网会导致请求失败，弱网会导致请求超时
 * 2、系统错误, 通常由于后端服务不能正常提供响应导致，如服务下线
 * 3、接口错误, 指的是由于请求本身问题导致接口返回了错误响应
 * 
 * 这里解决超时的方法有两种方式：
 * a) 使用AbortController超时中断
 * b) 使用promise接管fetch响应，然后reject
 */
import factory from './factory'

function serve({ serviceName, serviceArguments = {} }) {
  let {
    url,
    options,
  } = factory({ serviceName, serviceArguments })
  const controller = new AbortController()
  const signal = controller.signal

  // 超时实现方式a
  // setTimeout(() => {
  //   controller.abort() 
  // }, 10)
  // return fetch(url, { ...options, signal }).then(/*...*/).catch(/*...*/)

  return new Promise((resolve, reject) => {
    TIMEOUT_GUARD({ reject, controller })
    fetch(url, { ...options, signal }).then(resolve, reject)
  }).then(res => {
    const {
      ok,
      status,
      statusText,
    } = res
    if (ok) {
      return res.json().then(res => {
        const { code, mdg, reqid } = res
        if (code === 0) {
          return res
        } else {
          // 3类错误
          return {
            code: 9001,
            error: res,
          }
        }
      })
    } else {
      // 2类错误
      return {
        code: 8001,
        error: { status, statusText }
      }
    }
  }).catch(error => {
    // 1类错误
    // 使用第一种超时实现方式
    if (error.name === 'AbortError') {
      return {
        code: 7001,
        error,
      }
    }

    // 第二种超时实现方式
    if (error.code === 7002) {
      return error
    }

    // 其他请求错误，比如网络中断，
    return {
      code: 7000,
      error,
    }
  })
  // b方式超时, 定义拒绝约定
  function TIMEOUT_GUARD({ reject, controller}) {
    setTimeout(() => {
      reject({
        code: 7002,
        error: new Error('请求超时')
      }) 
      controller.abort()
    }, 10)
  }
}

export default new Proxy({}, {
  get(target, serviceName) {
    return serviceArguments => serve({ serviceName, serviceArguments })
  }
})